package com.ouroboroswiki.core.content.xml.repo.list;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.ouroboroswiki.core.AbstractContentRepository;
import com.ouroboroswiki.core.Content;
import com.ouroboroswiki.core.ContentException;
import com.ouroboroswiki.core.ContentPath;
import com.ouroboroswiki.core.ContentRepository;
import com.ouroboroswiki.core.ContentRepositoryFactory;
import com.ouroboroswiki.core.ContentUtil;
import com.ouroboroswiki.core.ListableContentRepository;
import com.ouroboroswiki.core.Version;
import com.ouroboroswiki.core.VersionBuilder;
import com.ouroboroswiki.core.WritableContentRepository;
import com.ouroboroswiki.core.content.xml.XMLDOMContent;

public class XMLListContentRepository extends AbstractContentRepository implements ListableContentRepository {
	
	public static final String ELEMENT_ROOT = "contentGroups";
	public static final String ELEMENT_CONTENT_GROUP = "contentGroup";
	public static final String ELEMENT_CONTENT = "content";
	public static final String ATTRIBUTE_CONTENT_ID = "id";
	public static final String ATTRIBUTE_REPO_ID = "name";
	public static final String ATTRIBUTE_REPO_WRITABLE = "writable";

	private TransformerFactory transformerFactory;
	private DocumentBuilderFactory documentBuilderFactory;
	private ContentRepositoryFactory repositoryFactory;
	
	public XMLListContentRepository( 
			TransformerFactory transformerFactory,
			DocumentBuilderFactory documentBuilderFactory
	) {
		this.documentBuilderFactory = documentBuilderFactory;
		this.transformerFactory = transformerFactory;
	}
	
	
	public void setRepositoryFactory(ContentRepositoryFactory repositoryFactory) {
		this.repositoryFactory = repositoryFactory;
	}



	@Override
	public Version buildVersion(Object principal, ContentPath path,
			String[] versionPath, VersionBuilder versionBuilder)
			throws ContentException {
		// TODO : probably not right, aggregate?
		String contentId = path.getBaseName();
		return versionBuilder.buildVersion(this.getName(), contentId, versionPath, 0);
	}

	@Override
	public boolean exists(Object principal, ContentPath path)
			throws ContentException {
		// probably exists
		return true;
	}

	@Override
	public Content getContent(Object principal, ContentPath path, Version version, Map<String, Object> properties)
			throws ContentException {
		// build a document containing all the content in the repository
		try {
			DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
			Document document = documentBuilder.newDocument();

			Element rootElement = document.createElement(ELEMENT_ROOT);
			document.appendChild(rootElement);

			ListableContentRepository contentRepository;
			List<ContentPath> basePaths = path.getBasePaths();
			for( int i=0; i<basePaths.size(); i++ ) {
				String baseName = basePaths.get(i).getName();
				contentRepository = (ListableContentRepository)this.repositoryFactory.getRepository( baseName );
				
				Collection<String> contentIds = contentRepository.listContentIds(principal);
				
				// TODO : should we use the path as a filter?
				Element contentGroupElement = document.createElement(ELEMENT_CONTENT_GROUP);
				contentGroupElement.setAttribute(ATTRIBUTE_REPO_ID, contentRepository.getName());
				contentGroupElement.setAttribute(ATTRIBUTE_REPO_WRITABLE, Boolean.toString(contentRepository instanceof WritableContentRepository));
				contentGroupElement.setTextContent(contentRepository.getDescription());
				rootElement.appendChild(contentGroupElement);
				
				for( String contentId : contentIds ) {
					Element contentElement = document.createElement(ELEMENT_CONTENT);
					contentElement.setAttribute(ATTRIBUTE_CONTENT_ID, contentId);
					contentGroupElement.appendChild( contentElement );
				}
				
			}
			
			XMLDOMContent content = new XMLDOMContent(document, transformerFactory);
			content.setRepositoryName( this.getName() );
			content.setAutoIndent(true);
			content.setUniqueName( ContentUtil.toString(basePaths) );
			return content;
		} catch( ParserConfigurationException ex ) {
			throw new ContentException( "unable to create document builder", ex );
		}
	}


	@Override
	public Collection<String> listContentIds(Object principal)
			throws ContentException {
		Collection<ContentRepository> repositories = repositoryFactory.getRepositories();
		ArrayList<String> contents = new ArrayList<String>(repositories.size());
		for( ContentRepository repository : repositories ) {
			String repositoryName = repository.getName();
			contents.add( repositoryName );
		}
		return contents;
	}

	
}
